#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <assert.h>
#include <sys/stat.h>

#include "settings_manager.h"
#include "ini_operation.h"

#define DECODER_KVM_CONFIG_INI_PATH			"/media/card/kvm.ini"
#define StreamMacAddress					"DeviceMACAddr"
#define SerialNumber						"SerialNumber"
#define DeviceShowName						"DeviceName"
#define DeviceUserName						"UserName"
#define DevicePasswd						"Passwd"
#define DEFAULT_MAC_ADDRESS					"00:C0:2F:11:22:33"
#define DEFAULT_SERIAL_NUMBER				"11223344556"
#define DEFAULT_DEVICE_NAME					"KVM"

typedef enum param_Type_t
{
	PARAM_NUM,
	PARAM_STR,
}paramType;

typedef union param_Value_t
{
	int val;
	char *str;
}paramValue;

typedef enum param_Index
{
	//network config
	Addressing = 0,
	CtrlIPAddr,
	CtrlMask,
	CtrlGateway,
	StreamIPAddr,
	StreamMask,
	StreamGateway,
	//ip input
	InputSource,
	IPRecvMode,
	IPPort,
	IPMulticastAddr,
	IPUnicastAddr,
	IPRTSPAddr,
	//srt input
	SRTMode,
	SRTCallerAddr,
	SRTPort,
	SRTLatency,
	SRTEncrpyt,
	SRTPassword,
	//vcu config
	VCUfmt,
	VCUGdrmode,
	VCUGOP,
	VCUMode,
	VCUFramerate,
	VCUHeight,
	VCUWidth,
	VCUBitrate,
	VCUAudioSwitch,
	//username and password
	UserName,
	PassWord,
	PingTest,
	//wifi
	WifiSwitch,
	WifiName,
	WifiPasswd,
	ParamIndexEnd,
}paramIndex;

typedef struct global_param_t
{
	paramIndex param_index;
	char *config_item;
	char *default_param;
	paramValue param_value;	//need lock mutex when access this member
	paramType param_type;
	int param_size;			//only for PARAM_STR type
	pthread_mutex_t *mutex;
}g_param;

static pthread_mutex_t ip_setting_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t input_setting_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t decoder_setting_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t time_setting_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t common_setting_mutex = PTHREAD_MUTEX_INITIALIZER;

static g_param g_param_array[] = {
	{
		Addressing,
		"Addressing",
		"0",
		{ 0 },
		PARAM_NUM,
		sizeof(int),
		&ip_setting_mutex,
	},
	{
		CtrlIPAddr,
		"CtrlIPAddr",
		"10.10.10.100",
		{0},
		PARAM_STR,
		IP_LEN,
		&ip_setting_mutex,
	},
	{
		CtrlMask,
		"CtrlMask",
		"255.255.255.0",
		{0},
		PARAM_STR,
		IP_LEN,
		&ip_setting_mutex,
	},
	{
		CtrlGateway,
		"CtrlGateway",
		"10.10.10.1",
		{0},
		PARAM_STR,
		IP_LEN,
		&ip_setting_mutex,
	},
	{
		StreamIPAddr,
		"StreamIPAddr",
		"192.168.1.100",
		{0},
		PARAM_STR,
		IP_LEN,
		&ip_setting_mutex,
	},
	{
		StreamMask,
		"StreamMask",
		"255.255.255.0",
		{0},
		PARAM_STR,
		IP_LEN,
		&ip_setting_mutex,
	},
	{
		StreamGateway,
		"StreamGateway",
		"192.168.1.1",
		{0},
		PARAM_STR,
		IP_LEN,
		&ip_setting_mutex,
	},
	{
		InputSource,
		"InputSource",
		"0",
		{ 0 },
		PARAM_NUM,
		sizeof(int),
		&input_setting_mutex,
	},
	{
		IPRecvMode,
		"IPRecvMode",
		"0",
		{0},
		PARAM_NUM,
		sizeof(int),
		&input_setting_mutex,
	},
	{
		IPPort,
		"IPPort",
		"1234",
		{0},
		PARAM_NUM,
		sizeof(int),
		&input_setting_mutex,
	},
	{
		IPMulticastAddr,
		"IPMulticastAddr",
		"239.0.0.1",
		{0},
		PARAM_STR,
		IP_LEN,
		&input_setting_mutex,
	},
	{
		IPUnicastAddr,
		"IPUnicastAddr",
		"192.168.1.100",
		{ 0 },
		PARAM_STR,
		IP_LEN,
		&input_setting_mutex,
	},
	{
		IPRTSPAddr,
		"RTSPAddress",
		"http",
		{ 0 },
		PARAM_STR,
		COMMON_LEN,
		&input_setting_mutex,
	},
	{
		SRTMode,
		"SRTMode",
		"0",
		{ 0 },
		PARAM_NUM,
		sizeof(int),
		&input_setting_mutex,
	},
	{
		SRTCallerAddr,
		"SRTCallerAddr",
		"192.168.1.101",
		{ 0 },
		PARAM_STR,
		IP_LEN,
		&input_setting_mutex,
	},
	{
		SRTPort,
		"SRTPort",
		"8006",
		{ 0 },
		PARAM_NUM,
		sizeof(int),
		&input_setting_mutex,
	},
	{
		SRTLatency,
		"SRTLatency",
		"200",
		{ 0 },
		PARAM_NUM,
		sizeof(int),
		&input_setting_mutex,
	},
	{
		SRTEncrpyt,
		"SRTEncrpyt",
		"0",
		{ 0 },
		PARAM_NUM,
		sizeof(int),
		&input_setting_mutex,
	},
	{
		SRTPassword,
		"SRTPassword",
		"1234567890",
		{ 0 },
		PARAM_STR,
		PASSWORD_LEN,
		&input_setting_mutex,
	},
	{
		VCUfmt,
		"VCUFMT",
		"0",
		{ 0 },
		PARAM_NUM,
		sizeof(int),
		&decoder_setting_mutex,
	},
	{
		VCUGdrmode,
		"GDRMode",
		"0",
		{ 0 },
		PARAM_NUM,
		sizeof(int),
		&decoder_setting_mutex,
	},
	{
		VCUGOP,
		"GOP",
		"60",
		{ 0 },
		PARAM_NUM,
		sizeof(int),
		&decoder_setting_mutex,
	},
	{
		VCUMode,
		"Mode",
		"0",
		{ 0 },
		PARAM_NUM,
		sizeof(int),
		&decoder_setting_mutex,
	},
	{
		VCUFramerate,
		"framerate",
		"60",
		{ 0 },
		PARAM_NUM,
		sizeof(int),
		&decoder_setting_mutex,
	},
	{
		VCUHeight,
		"height",
		"1080",
		{ 0 },
		PARAM_NUM,
		sizeof(int),
		&decoder_setting_mutex,
	},
	{
		VCUWidth,
		"width",
		"1920",
		{ 0 },
		PARAM_NUM,
		sizeof(int),
		&decoder_setting_mutex,
	},
	{
		VCUBitrate,
		"bitrate",
		"5000",
		{ 0 },
		PARAM_NUM,
		sizeof(int),
		&decoder_setting_mutex,
	},
	{
		VCUAudioSwitch,
		"audioswitch",
		"0",
		{ 0 },
		PARAM_NUM,
		sizeof(int),
		&decoder_setting_mutex,
	},
	{
		UserName,
		"UserName",
		"admin",
		{0},
		PARAM_STR,
		COMMON_LEN,
		&decoder_setting_mutex,
	},
	{
		PassWord,
		"PassWord",
		"webmanager",
		{0},
		PARAM_STR,
		COMMON_LEN,
		&decoder_setting_mutex,
	},
	{
		PingTest,
		"PingTest",
		"192.168.1.101",
		{0},
		PARAM_STR,
		IP_LEN,
		&ip_setting_mutex,
	},
	{
		WifiSwitch,
		"wifi_switch",
		"0",
		{ 0 },
		PARAM_NUM,
		sizeof(int),
		&decoder_setting_mutex,
	},
	{
		WifiName,
		"Wifi_name",
		"wifi",
		{ 0 },
		PARAM_STR,
		COMMON_LEN,
		&decoder_setting_mutex,
	},
	{
		WifiPasswd,
		"Wifi_passwd",
		"test",
		{ 0 },
		PARAM_STR,
		COMMON_LEN,
		&decoder_setting_mutex,
	}
};


static int get_param_setting(paramIndex index, void *val);
static int set_param_setting(paramIndex index, void *val);

void default_setting_init()
{
	printf("Enter %s\n", __func__);
	int i;
	int err_cnt = 0;
	char ini_err[ParamIndexEnd];
	char second_read_err_cnt = 0;
	int param_count = sizeof(g_param_array)/sizeof(g_param);

	for(i = 0; i < param_count; i++)
	{
		g_param *param = &g_param_array[i];

		if(param->param_type == PARAM_NUM)
		{

			int val = atoi(param->default_param);
			set_param_setting(i, &val);
		}
		else if(param->param_type == PARAM_STR)
		{
			param->param_value.str = (char* )malloc(param->param_size);
			memset(param->param_value.str, 0, param->param_size);
			set_param_setting(i, param->default_param);
		}
		else
		{
			assert(0);
		}
	}
}

int get_param_setting(paramIndex index, void *val)
{
	assert(index < ParamIndexEnd);
	int ret = 0;
	g_param *param = &g_param_array[index];

	pthread_mutex_lock(param->mutex);
	if(param->param_type == PARAM_NUM)
	{
		ret = param->param_value.val;
		if (NULL != val)
		{
			*(int *)val = ret;
		}
	}
	else if(param->param_type == PARAM_STR)
	{
		assert(NULL != val);
		strcpy((char *)val, param->param_value.str);
	}
	else
	{
		assert(0);
	}
	pthread_mutex_unlock(param->mutex);

	if(param->param_type == PARAM_NUM)
	{
		//log_printf(LOG_ALL_OUT, LOG_LEVEL_INFO, "<%s> %s : %d.\n", __func__, param->config_item, *(int *)val);
	}
	else
	{
		//log_printf(LOG_ALL_OUT, LOG_LEVEL_INFO, "<%s> %s : %s.\n", __func__, param->config_item, (char *)val);
	}

	return ret;
}


int set_param_setting(paramIndex index, void *val)
{
	assert(index < ParamIndexEnd);
	assert(NULL != val);
	g_param *param = &g_param_array[index];

	pthread_mutex_lock(param->mutex);
	if(param->param_type == PARAM_NUM)
	{
		param->param_value.val = *(int *)val;
	}
	else if(param->param_type == PARAM_STR)
	{
		assert(strlen((char *)val) < param->param_size);
		strcpy(param->param_value.str, (char *)val);
	}
	else
	{
		assert( 0);
	}
	pthread_mutex_unlock(param->mutex);

	return 0;
}

/************************** Add the access parameter interface from here **************************/
//network------------------------
int get_ip_addressing_setting(int *val)
{
	return get_param_setting(Addressing, val);
}

int set_ip_addressing_setting(int val)
{
	return set_param_setting(Addressing, &val);
}

int get_ctrl_ipaddr_setting(char *ip_addr)
{
	return get_param_setting(CtrlIPAddr, ip_addr);
}

int set_ctrl_ipaddr_setting(char *ip_addr)
{
	return set_param_setting(CtrlIPAddr, ip_addr);
}

int get_ctrl_mask_setting(char *mask)
{
	return get_param_setting(CtrlMask, mask);
}

int set_ctrl_mask_setting(char *mask)
{
	return set_param_setting(CtrlMask, mask);
}

int get_ctrl_gateway_setting(char *gateway)
{
	return get_param_setting(CtrlGateway, gateway);
}

int set_ctrl_gateway_setting(char *gateway)
{
	return set_param_setting(CtrlGateway, gateway);
}

int get_stream_ipaddr_setting(char *ip_addr)
{
	return get_param_setting(StreamIPAddr, ip_addr);
}

int set_stream_ipaddr_setting(char *ip_addr)
{
	return set_param_setting(StreamIPAddr, ip_addr);
}

int get_stream_mask_setting(char *mask)
{
	return get_param_setting(StreamMask, mask);
}

int set_stream_mask_setting(char *mask)
{
	return set_param_setting(StreamMask, mask);
}

int get_stream_gateway_setting(char *gateway)
{
	return get_param_setting(StreamGateway, gateway);
}

int set_stream_gateway_setting(char *gateway)
{
	return set_param_setting(StreamGateway, gateway);
}

//Output----------
int get_input_source_setting(int *val)
{
	return get_param_setting(InputSource, val);
}

int set_input_source_setting(int val)
{
	return set_param_setting(InputSource, &val);
}

int get_iprecv_mode_setting(int *val)
{
	return get_param_setting(IPRecvMode, val);
}

int set_iprecv_mode_setting(int val)
{
	return set_param_setting(IPRecvMode, &val);
}

int get_ip_port_setting(int *val)
{
	return get_param_setting(IPPort, val);
}

int set_ip_port_setting(int val)
{
	return set_param_setting(IPPort, &val);
}

int get_ip_multicastaddr_setting(char *addr)
{
	return get_param_setting(IPMulticastAddr, addr);
}

int set_ip_multicastaddr_setting(char *addr)
{
	return set_param_setting(IPMulticastAddr, addr);
}

int get_ip_unicastaddr_setting(char *addr)
{
	return get_param_setting(IPUnicastAddr, addr);
}

int set_ip_unicastaddr_setting(char *addr)
{
	return set_param_setting(IPUnicastAddr, addr);
}

int get_rtspaddr_setting(char *addr)
{
	return get_param_setting(IPRTSPAddr, addr);
}

int set_rtspaddr_setting(char *addr)
{
	return set_param_setting(IPRTSPAddr, addr);
}

int get_srt_mode_setting(int *val)
{
	return get_param_setting(SRTMode, val);
}

int set_srt_mode_setting(int val)
{
	return set_param_setting(SRTMode, &val);
}

int get_srt_calleraddr_setting(char *addr)
{
	return get_param_setting(SRTCallerAddr, addr);
}

int set_srt_calleraddr_setting(char *addr)
{
	return set_param_setting(SRTCallerAddr, addr);
}

int get_srt_port_setting(int *val)
{
	return get_param_setting(SRTPort, val);
}

int set_srt_port_setting(int val)
{
	return set_param_setting(SRTPort, &val);
}

int get_srt_latency_setting(int *val)
{
	return get_param_setting(SRTLatency, val);
}

int set_srt_latency_setting(int val)
{
	return set_param_setting(SRTLatency, &val);
}

int get_srt_encrpyt_setting(int *val)
{
	return get_param_setting(SRTEncrpyt, val);
}

int set_srt_encrpyt_setting(int val)
{
	return set_param_setting(SRTEncrpyt, &val);
}

int get_srt_password_setting(char *passwd)
{
	return get_param_setting(SRTPassword, passwd);
}

int set_srt_password_setting(char *passwd)
{
	return set_param_setting(SRTPassword, passwd);
}

//VCU
int get_video_fmt_setting(int *val)
{
	return get_param_setting(VCUfmt, val);
}

int set_video_fmt_setting(int val)
{
	return set_param_setting(VCUfmt, &val);
}

int get_video_gdrmode_setting(int *val)
{
	return get_param_setting(VCUGdrmode, val);
}

int set_video_gdrmode_setting(int val)
{
	return set_param_setting(VCUGdrmode, &val);
}

int get_video_gop_setting(int *val)
{
	return get_param_setting(VCUGOP, val);
}

int set_video_gop_setting(int val)
{
	return set_param_setting(VCUGOP, &val);
}

int get_video_mode_setting(int *val)
{
	return get_param_setting(VCUMode, val);
}

int set_video_mode_setting(int val)
{
	return set_param_setting(VCUMode, &val);
}

int get_video_framerate_setting(int *val)
{
	return get_param_setting(VCUFramerate, val);
}

int set_video_framerate_setting(int val)
{
	return set_param_setting(VCUFramerate, &val);
}

int get_video_height_setting(int *val)
{
	return get_param_setting(VCUHeight, val);
}

int set_video_height_setting(int val)
{
	return set_param_setting(VCUHeight, &val);
}

int get_video_width_setting(int *val)
{
	return get_param_setting(VCUWidth, val);
}

int set_video_width_setting(int val)
{
	return set_param_setting(VCUWidth, &val);
}

int set_decoder_audioswitch_setting(int val)
{
	return set_param_setting(VCUAudioSwitch, &val);
}

int get_decoder_audioswitch_setting(int *val)
{
	return get_param_setting(VCUAudioSwitch, val);
}

int set_decoder_bitrate_setting(int val)
{
	return set_param_setting(VCUBitrate, &val);
}

int get_decoder_bitrate_setting(int *val)
{
	return get_param_setting(VCUBitrate, val);
}

//login
int get_decoder_username_setting(char *user)
{
	return get_param_setting(UserName, user);
}

int set_decoder_username_setting(char *user)
{
	return set_param_setting(UserName, user);
}

int get_decoder_password_setting(char *pass)
{
	return get_param_setting(PassWord, pass);
}

int set_decoder_password_setting(char *pass)
{
	return set_param_setting(PassWord, pass);
}

//system-------------
int get_ping_address_setting(char *addr)
{
	return get_param_setting(PingTest, addr);
}

int set_ping_address_setting(char *addr)
{
	return set_param_setting(PingTest, addr);
}

int get_wifi_switch_setting(int *val)
{
	return get_param_setting(WifiSwitch, val);
}

int set_wifi_switch_setting(int val)
{
	return set_param_setting(WifiSwitch, &val);
}

int get_wifi_name_setting(char *pass)
{
	return get_param_setting(WifiName, pass);
}

int set_wifi_name_setting(char *pass)
{
	return set_param_setting(WifiName, pass);
}

int get_wifi_passwd_setting(char *pass)
{
	return get_param_setting(WifiPasswd, pass);
}

int set_wifi_passwd_setting(char *pass)
{
	return set_param_setting(WifiPasswd, pass);
}


/************************** Add the access serial number and mac address from here **************************/

int get_mac_address_setting(char *mac)
{
	if (0 != read_ini_str(StreamMacAddress, DECODER_KVM_CONFIG_INI_PATH, mac))
	{
		printf("%s:read mac address error,use default address:%s\n", __func__, DEFAULT_MAC_ADDRESS);
		strcpy(mac, DEFAULT_MAC_ADDRESS);
	}
	return 0;
}

int get_serial_number_setting(char *serial)
{
	if (0 != read_ini_str(SerialNumber, DECODER_KVM_CONFIG_INI_PATH, serial))
	{
		printf("%s:read serial number error,use default number:%s\n", __func__, DEFAULT_SERIAL_NUMBER);
		strcpy(serial, DEFAULT_SERIAL_NUMBER);
	}
	return 0;
}

int get_decoder_device_showname_setting(char *val)
{
	if (0 != read_ini_str(DeviceShowName, DECODER_KVM_CONFIG_INI_PATH, val))
	{
		printf("%s:read device name error,use default name:%s\n", __func__, DEFAULT_DEVICE_NAME);
		strcpy(val, DEFAULT_DEVICE_NAME);
	}
	return 0;
}

int get_kvm_username_setting(char *val)
{
	if (0 != read_ini_str(DeviceUserName, DECODER_KVM_CONFIG_INI_PATH, val))
	{
		printf("%s:read device name error,use default name:%s\n", __func__, "admin");
		strcpy(val, "admin");
	}
	return 0;
}

int get_kvm_passwd_setting(char *val)
{
	if (0 != read_ini_str(DevicePasswd, DECODER_KVM_CONFIG_INI_PATH, val))
	{
		printf("%s:read device name error,use default name:%s\n", __func__, "webmanager");
		strcpy(val, "webmanager");
	}
	return 0;
}

int set_kvm_passwd_setting(char *val)
{
	if (0 != modify_ini(DevicePasswd, val, DECODER_KVM_CONFIG_INI_PATH))
	{
		printf("Write param to ini failed. The setting will lost after restart.\n");
	}
	return 0;
}

int get_decoder_fpga_version_setting(char *val)
{
	sprintf(val, "%s.%s.%s.%s", "10", "0", "0", "1");
	return 0;
}

int get_decoder_app_version_setting(char *val)
{
	sprintf(val, "%s.%s.%s.%s", "10", "0", "0", "1");
	return 0;
}

int get_zynqmp_cpu_temp_value()
{
	char buf[20];
	char *str;
	int value = 0;
	FILE* flp = fopen("/sys/bus/iio/devices/iio:device0/in_temp0_ps_temp_raw", "r");
	if (NULL == flp)
	{
		printf("open Ini file failed %s\n", __func__);
		return -1;
	}
	str = fgets(buf, 20, flp);
	fclose(flp);
	value = ((atoi(str) * 509.314) / 65536.0) - 280.23;
	return value;
}